/**
 *	@file	stdext.h
 *
 *	@brief	the extension APIs for standard library
 *	
 *	@author	Forrest.zhang
 *
 *	@date
 */

#ifndef FZ_STDEXT_H
#define FZ_STDEXT_H

/**
 *	Define likely()/unlikely() for performance.
 */
#ifndef	likely
#define	likely(x)	__builtin_expect(!!(x), 1)
#endif

#ifndef	unlikely
#define	unlikely(x)	__builtin_expect(!!(x), 0)
#endif


/***********************************************************
 *	Safety String functions. all string must Zero-end.
 **********************************************************/
/*----------------------------------------------------------
 |	String array:
 |      ptr1 --> string1
 |      ptr2 --> string2
 |	..............
 |	ptrN --> NULL(end of array)
 |
 |--------------------------------------------------------*/

/**
 *	Free string array @str and all alloced memory 
 *	inside it.
 *
 *	Return 0 if success, -1 on error.
 */
extern int 
str_array_free(char **array);

/**
 *	Return string @str length. 
 *
 *	Return >= 0 is success, -1 on error or @str is 
 *	not zero-end.
 */
extern int 
str_len(const char *str, size_t len);

/**
 *	Copy string @src to destination string @dst, the 
 *	@dst length is @dlen. The @src length is @slen. 
 *	@dst is zero-end after copy.
 *
 *	Return copied char number if success, -1 on error 
 *	or @src/@dst is not zero-end.
 */
extern int  
str_copy(char *dst, size_t dlen, const char *str, size_t slen);

/**
 *	Append string @src to string @dst, the @dst length
 *	is @dlen, the @src length is @slen.
 *	The @dst is zero-end after append.
 *	
 *	Return the copied bytes number if success, -1 error 
 *	or @src/@dst is not zero-end.
 */
extern int 
str_cat(char *dst, size_t dlen, const char *src, size_t slen);

/**
 *	Compare string @str1 and @str2.
 *
 *	Return 0 if them have same value, or else not same value.
 */
extern int 
str_cmp(const char *str1, size_t len1, const char *str2, size_t len2);

/**
 *	Find first char @c in string @str, @str length is 
 *	@len.
 *
 *	Return pointer to first @c, NULL not found or error
 *	or @str is not zero-end.
 */
extern char *  
str_chr(const char *str, size_t len, char c);

/**
 *	Find last char @c in string @str, @str length is 
 *	@len
 *
 *	Return pointer to last @c, NULL if not found or 
 *	error or @str is not zero-end.
 */
extern char *
str_rchr(const char *str, size_t len, char c);

/**
 *	Find the first substring @substr in string @str, 
 *	@str length is @len, @substr length is @slen. 
 *	Using case-sensitive compare.
 *
 *	Return pointer to found substring in @str if found.
 *	NULL if not found or error or @str/@substr is not 
 *	zero-end.
 */
extern char *
str_str(const char *str, size_t len, const char *substr, size_t slen);

/**
 *	Find the last substring @substr in string @str, 
 *	@str length is @len, @substr length is @slen
 *	Using case-sensitive compare.
 *
 *	Return pointer to found substring in @str if found.
 *	NULL if not found or error or @str/@substr is not 
 *	zero-end.
 */
extern char *
str_rstr(const char *str, size_t len, const char *substr, size_t slen);

/**
 *	Find the first substring @substr in string @str, 
 *	@str length is @len, @substr length is @slen 
 *	using case-insensitive compare
 *
 *	Return pointer to found substring in @str if found.
 *	NULL if not found or error or @str/@substr is not 
 *	zero-end.
 */
extern char *
str_casestr(const char *str, size_t len, const char *substr, size_t slen);

/**
 *	Find the last substring @substr in string @str, 
 *	@str length is @len, @substr length is @slen
 *	Using case-insensitive compare. 
 *
 *	Return pointer to found substring in @str if found.
 *	NULL if not found or error or @str/@substr is not 
 *	zero-end.
 */
extern char *
str_caserstr(const char *str, size_t len, const char *substr, size_t slen);

/**
 *	Free the malloced string array @array.
 *
 *	Return 0 if success, -1 on error.
 */
extern int 
str_free_array(char **array);

/**
 *	Tokenize string @str by delim chars @delim.
 *	Return current token and set @off to next token start.  
 *
 *	This function will modify @str's @delim chars to '0'.
 *
 *	The first time call need set @str, the all next time 
 *	calls need set @str as NULL and keep @off not touched.
 *
 *	Return the current token string if success, NULL on no 
 *	more token or error or @str is not zero-end.
 */
extern char * 
str_token(char *str, size_t len, const char *delim, size_t dlen, char **off);

/**
 *	Check all characters in string @str is space 
 *	char(isspace()).
 *
 *	Return 1 if all chars is space char, 0 if not or
 *	@str is not zero-end.
 */
extern int 
str_is_blank(const char *str, size_t len);

/**
 *	Stripped string @str leading space char.
 *
 *	Return pointer to first non-space char if success.
 *	NULL if failed or error or all chars are space 
 *	chars or @str is not zero-end.
 */
extern char * 
str_strip_begin(const char *str, size_t len);

/**
 *	Stripped string @str tailing space char.
 *
 *	Return pointer to last non-space char if success.
 *	NULL if failed or error or all chars are space 
 *	chars or @str is not zero-end.
 */
extern char * 
str_strip_end(const char *str, size_t len);



/**
 *	Copy memory @src to @dst. @src and @dst can overlap. 
 *	@src length is @slen, @dst length is @dlen.
 *
 *	Return >= 0 if success, -1 on error.
 */
extern int 
mem_copy(void *dst, size_t dlen, const void *src, size_t slen);

/**
 *	Find first unsigned char @c in memory @str.
 *
 *	Return address to find @c if success, NULL
 *	on error or not found.
 */
extern void * 
mem_chr(const void *str, size_t len, unsigned char c);

/**
 *	Find last unsigned char @c in memory @str.
 *
 *	Return address to find @c if success, NULL
 *	on error or not found.
 */
extern void * 
mem_rchr(const void *str, size_t len, unsigned char c);


/***********************************************************
 *	File and directory functions
 **********************************************************/

/**
 *	Remove all files/directories in directory @dir except 
 *	files/directory in string array @execptions.
 *
 *	Return if success, -1 on error.
 */
extern int 
dir_empty(const char *dir, const char *exceptions[]);

/**
 *	Create a new directory @dir, if the ancient path of @dir
 *	is not exist, also created. All new create directory mode
 *	is @mode.
 *
 *	Return 0 if success, -1 on error.
 */
extern int 
dir_create(const char *dir, int mode);

/**
 *	Remove directory @dir and files/directories in it.
 *
 *	Return 0 if success, -1 on error.
 */
extern int 
dir_remove(const char *dir);

/**
 *	Copy directory @srcdir and all files/directories in 
 *	it to directory @dstdir, if @dstdir not exist, 
 *	create it.
 *
 *	Return 0 if success, -1 on error.
 */
extern int 
dir_copy(const char *dstdir, const char *srcdir);

/**
 *	Get all files in directory @dir.
 *
 *	Need call str_free_array() returned string array.
 *
 *	Return string array of files if success, -1 on error.
 */
extern char ** 
dir_files(const char *dir);

/**
 *	Get all directories in directory @dir
 *
 *	Need call str_array_free() after use.
 * 
 *	Return string array of directories if success, -1 on error.
 */
extern char ** 
dir_dirs(const char *dir);


#endif /* end of FZ_STDEXT_H  */


